package com.bdqn.util;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import lombok.Data;

import java.io.File;
import java.io.InputStream;
import java.util.*;

/**
 * ExcelUtil Excel工具类（基于EasyExcel监听器模式，可处理大文件）
 *
 * @author LILIBO
 * @since 2021-06-24
 */
public class ExcelUtil {

    public static void main(String[] args) throws Exception {
        // 测试原生EasyExcel案例
        // ExcelUtil.testEasyExcelDemo();

        // 设置Excel文件名称
        String fileName = "D:/Temp/Test01.xlsx";

        // 准备写入Excel的数据
        /* List<StaffXo> list = new ArrayList<>();
        for (int i = 0; i < 9; i++) {
            StaffXo data = new StaffXo();
            data.setNo(i + 1);
            data.setName("员工 " + (i + 1));
            list.add(data);
        } */

        // 将数据写入Excel（数据实体参考ExcelXo封装，表头自动写入）
        /* boolean result = ExcelUtil.writeExcel(fileName, list, StaffXo.class);
        System.out.println(result ? "Excel写入成功！" : "Excel写入失败！"); */

        // 读取Excel数据到实体（数据实体参考ExcelXo封装）
        /* List<StaffXo> readData = ExcelUtil.readData(fileName, StaffXo.class);
        for (StaffXo xo : readData) {
            System.out.println(xo);
        } */

        // 读取Excel表头信息
        /* Map<Integer, String> readHead = ExcelUtil.readHead(fileName);
        System.out.println(readHead); */

        // 读取Excel数据信息
        List<Map<String, String>> readData = ExcelUtil.readData(fileName);
        for (Map<String, String> readDatum : readData) {
            System.out.println(readDatum);
        }



    }

    /**
     * 读取Excel表头信息
     *
     * @param fileName Excel文件全路径
     * @return Excel表头信息（第一行数据）
     */
    public static Map<Integer, String> readHead(String fileName) {
        // 创建Excel读取监听器
        ExcelListener excelListener = new ExcelListener<>();
        // 读取Excel数据
        EasyExcel.read(fileName, excelListener).sheet().doRead();
        // 返回读取到的表头信息（第一行）
        return excelListener.headMap;
    }

    /**
     * 读取Excel数据到实体（数据实体参考ExcelXo封装）
     *
     * @param fileName Excel文件全路径
     * @return Excel数据（从第二行开始）
     */
    public static List<Map<String, String>> readData(String fileName) {
        // 创建Excel读取监听器
        ExcelListener excelListener = new ExcelListener<>();
        // 读取Excel数据
        EasyExcel.read(fileName, excelListener).sheet().doRead();
        // 返回读取到的表头信息（第一行）
        Map<Integer, String> headMap = excelListener.headMap;
        // 返回读取到的数据集合（从第二行开始）
        List<LinkedHashMap<Integer, String>> readList = excelListener.dataList;
        // 提取数据封装并返回
        List<Map<String, String>> dataList = new ArrayList<>();
        for (LinkedHashMap<Integer, String> dataMap : readList) {
            Map<String, String> hashMap = new HashMap<>();
            for (Integer i : headMap.keySet()) {
                hashMap.put(headMap.get(i), dataMap.get(i));
            }
            dataList.add(hashMap);
        }
        return dataList;
    }

    /**
     * 读取Excel数据到实体（数据实体参考ExcelXo封装）
     *
     * @param fileName Excel文件全路径
     * @param target 数据实体类型
     * @return Excel数据（从第二行开始）
     */
    public static List readData(String fileName, Class target) {
        // 创建Excel读取监听器
        ExcelListener excelListener = new ExcelListener();
        // 读取Excel数据
        EasyExcel.read(fileName, target, excelListener).sheet().doRead();
        // 返回读取到的数据集合（从第二行开始）
        return excelListener.dataList;
    }

    /**
     * 读取Excel数据到实体（数据实体参考ExcelXo封装）
     *
     * @param file Excel文件
     * @param target 数据实体类型
     * @return Excel数据（从第二行开始）
     */
    public static List readData(File file, Class target) {
        // 创建Excel读取监听器
        ExcelListener excelListener = new ExcelListener();
        // 读取Excel数据
        EasyExcel.read(file, target, excelListener).sheet().doRead();
        // 返回读取到的数据集合（从第二行开始）
        return excelListener.dataList;
    }

    /**
     * 读取Excel数据到实体（数据实体参考ExcelXo封装）
     *
     * @param inputStream Excel文件流
     * @param target 数据实体类型
     * @return Excel数据（从第二行开始）
     */
    public static List readData(InputStream inputStream, Class target) {
        // 创建Excel读取监听器
        ExcelListener excelListener = new ExcelListener();
        // 读取Excel数据
        EasyExcel.read(inputStream, target, excelListener).sheet().doRead();
        // 返回读取到的数据集合（从第二行开始）
        return excelListener.dataList;
    }

    /**
     * 将数据写入Excel（数据实体参考ExcelXo封装，表头自动写入）
     *
     * @param fileName Excel文件全路径
     * @param list 数据集合
     * @param target 对应数据实体类型
     * @return 写入成功
     */
    public static boolean writeExcel(String fileName, List list, Class target) {
        // 将数据写入Excel（sheetName默认为：工作表）
        return writeExcel(fileName, "工作表", list, target);
    }

    /**
     * 将数据写入Excel（数据实体参考ExcelXo封装，表头自动写入）
     *
     * @param fileName Excel文件全路径
     * @param sheetName 工作表名称
     * @param list 数据集合
     * @param target 对应数据实体类型
     * @return 写入成功
     */
    public static boolean writeExcel(String fileName, String sheetName, List list, Class target) {
        // 将数据写入Excel
        EasyExcel.write(fileName, target).sheet(sheetName).doWrite(list);
        return true;
    }


    /**
     * 原生EasyExcel案例（测试时先将ExcelXo实体类抽离到外部，再在main方法中调用，可查看效果）
     */
    private static void testEasyExcelDemo() {
        // 设置Excel文件名称
        String fileName = "D:/EasyExcelDemo.xlsx";

        List<ExcelXo> list = new ArrayList<>();
        for (int i = 0; i < 9; i++) {
            ExcelXo data = new ExcelXo();
            data.setNo(i + 1);
            data.setName("So Easy " + (i + 1));
            list.add(data);
        }
        // 将数据写入Excel
        EasyExcel.write(fileName, ExcelXo.class).sheet("工作表").doWrite(list);

        ExcelListener excelListener = new ExcelListener();
        EasyExcel.read(fileName, ExcelXo.class, excelListener).sheet().doRead();
        // 读取到的表头信息
        System.out.println(excelListener.headMap);
        // 读取到的数据集合
        List<ExcelXo> dataList = excelListener.dataList;
        for (ExcelXo excelXo : dataList) {
            System.out.println(excelXo);
        }
    }

    /**
     * ExcelXo数据封装类（根据表格数据封装到实体，参考本类在pojo中创建）
     *
     * @author LILIBO
     * @since 2021-06-24
     */
    @Data
    static class ExcelXo {

        @ExcelProperty(value = "编号", index = 0) // index表示列的下标，从0开始；列名为：编号
        private int no;

        @ExcelProperty(value = "姓名", index = 1)
        private String name;

    }

    /**
     * Excel读取监听器
     *
     * @param <T> 数据对应的实体类型
     */
    private static class ExcelListener<T> extends AnalysisEventListener<T> {

        /**
         * 表头信息
         */
        Map<Integer, String> headMap = new HashMap<>();

        /**
         * 数据集合
         */
        List<T> dataList = new ArrayList<>();

        /**
         * 读取表头信息（第一行即为表头）
         *
         * @param headMap
         * @param context
         */
        @Override
        public void invokeHeadMap(Map<Integer, String> headMap, AnalysisContext context) {
            this.headMap = headMap; // 设置读取到的表头信息
        }

        /**
         * 一行一行的读取数据（从第二行开始）
         *
         * @param data
         * @param context
         */
        @Override
        public void invoke(T data, AnalysisContext context) {
            dataList.add(data); // 将读取到的数据添加到集合
        }

        /**
         * 读取完毕之后
         *
         * @param context
         */
        @Override
        public void doAfterAllAnalysed(AnalysisContext context) {
        }

    }

}
